home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / FILER / SMART.ZIP / !SmartDir / c / pattern < prev   
Text File  |  1998-01-15  |  8KB  |  351 lines

  1. #include <ctype.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include "OS:osfile.h"
  6. #include "OS:osfscontro.h"
  7. #include "OS:osgbpb.h"
  8. #include "cmos.h"
  9. #include "pattern.h"
  10.  
  11. #ifndef NDEBUG
  12. #include <stdarg.h>
  13. #include <stdio.h>
  14. #include "OS:wimp.h"
  15. #endif
  16.  
  17.  
  18. static char *patterns = 0;
  19. static int patterns_size;
  20.  
  21. const os_error nomem_error = {0, "Not enough memory"};
  22. const os_error nofile_error = {0, "File not found or is a directory"};
  23. const os_error syntax_error = {0,
  24.   "*SmartOpenDir <full dirname> [<x> <y> [<width> <height>]] [<switches>]"};
  25. /*static const os_error pattern_error = {0, "Bad pattern file"};*/
  26.  
  27. #ifndef NDEBUG
  28. static void report(const char *report, ...)
  29. {
  30.   os_error err;
  31.   va_list va;
  32.  
  33.   va_start(va, report);
  34.   vsprintf(err.errmess, report, va);
  35.   va_end(va);
  36.   xwimp_report_error(&err, 1, "SmartOpenDir", 0);
  37. }
  38. #endif
  39.  
  40. os_error const *load_patterns(char const *filename)
  41. {
  42.   int i;
  43.   os_error *e = xosfile_read_stamped(filename, &i, 0, 0,
  44.       &patterns_size, 0, 0);
  45.   if (e) return e;
  46.   if (i != 1)
  47.     return &nofile_error;
  48.  
  49.   patterns = realloc(patterns, patterns_size + 1);
  50.   if (!patterns)
  51.     return &nomem_error;
  52.   e = xosfile_load_stamped(filename, (byte *) patterns,
  53.       0, 0, 0, 0, 0);
  54.   if (e) return e;
  55.  
  56.   /* Change patterns to make it easier to process */
  57.   for (i = 0; i < patterns_size; ++i)
  58.   {
  59.     if (iscntrl(patterns[i]))
  60.     {
  61.       if (patterns[i] == '\t')
  62.         patterns[i] = ' ';
  63.       else
  64.         patterns[i] = 0;
  65.     }
  66.     else
  67.       patterns[i] = tolower(patterns[i]);
  68.   }
  69.   if (patterns[patterns_size - 1] != 0)
  70.     patterns[patterns_size++] = 0;
  71.  
  72.   return 0;
  73. }
  74.  
  75. void free_patterns()
  76. {
  77.   free(patterns);
  78.   patterns = 0;
  79. }
  80.  
  81. bool match_pattern(char const *directory, char const *pattern)
  82. {
  83.   char canon[256];    /* Canonicalised directory name */
  84.   int i, j;
  85.   int lmi = -1, lmj = -1;    /* Last place where i & j matched for * */
  86.  
  87.   if (xosfscontrol_canonicalise_path(directory, canon, 0, 0, sizeof(canon), 0))
  88.     return FALSE;
  89. #ifndef NDEBUG
  90.   report("Matching directory \"%s\" against pattern \"%s\"\n", canon, pattern);
  91. #endif
  92.   for (i = 0, j = 0; ; )
  93.   {
  94.     switch (pattern[j])
  95.     {
  96.       case '*':
  97.         lmj = j++;
  98.         if (pattern[j] <= ' ')
  99.           return TRUE;
  100.         while (tolower(canon[i]) != pattern[j] && canon[i] > ' ')
  101.           ++i;
  102.         if (canon[i] <= ' ')
  103.           return FALSE;
  104.         lmi = i;
  105.         break;
  106.       case '%':
  107.         while (canon[i] != '.' && canon[i] > ' ')
  108.           ++i;
  109.         ++j;
  110.         if (canon[i] <= ' ' && pattern[j] <= ' ')
  111.           return TRUE;
  112.         break;
  113.       case '#':
  114.         ++j;
  115.         ++i;
  116.         break;
  117.       case '\\':
  118.         ++j;
  119.       default:
  120.         if (canon[i] <= ' ' && pattern[j] <= ' ')
  121.           return TRUE;
  122.         if (tolower(canon[i]) != pattern[j])
  123.         {
  124.           if (lmi == -1)
  125.             return FALSE;
  126.           else
  127.           {
  128.             i = ++lmi;
  129.             j = lmj;
  130.             break;
  131.           }
  132.         }
  133.         ++i;
  134.         ++j;
  135.     }
  136.   }
  137.   return FALSE;
  138. }
  139.  
  140. /* Find directory name in command *tail* */
  141. static os_error const *find_directory(char const *command,
  142.     char const **directory)
  143. {
  144.   *directory = strstr(command, "-directory ");
  145.   if (*directory)
  146.     *directory += 11;
  147.   else
  148.   {
  149.     *directory = strstr(command, "-dir ");
  150.     if (*directory)
  151.       *directory += 5;
  152.   }
  153.   if (!*directory)
  154.   {
  155.     *directory = command;
  156.     if (*command == '-')
  157.       return &syntax_error;
  158.   }
  159.   return 0;
  160. }
  161.  
  162. /* Find effective start of current line */
  163. static int line_start(int i)
  164. {
  165.   while (i < patterns_size)
  166.   {
  167.     /* Find end of current line */
  168.     /* Skip all blank lines */
  169.     while (i < patterns_size && !patterns[i]) ++i;
  170.     if (i == patterns_size)
  171.       return i;
  172.     /* Skip whitespace */
  173.     while (isspace(patterns[i])) ++i;
  174.     /* Skip comments */
  175.     if (patterns[i] == '#')
  176.     {
  177.       while (i < patterns_size && patterns[i++]);
  178.       /* Back round loop in case next line is also blank/comment */
  179.       continue;
  180.     }
  181.   #ifndef NDEBUG
  182.     report("Pattern line: \"%s\"\n", &patterns[i]);
  183.   #endif
  184.     return i;
  185.   }
  186.   return i;
  187. }
  188.  
  189. static int next_line(int i)
  190. {
  191.   /* Find end of current line */
  192.   while (i < patterns_size && patterns[i++]);
  193.   return i;
  194. }
  195.  
  196. int match_patterns(char const *directory)
  197. {
  198.   int i;
  199.   int cmos;
  200.  
  201.   if (!patterns)
  202.     return -1;
  203.   for (i = 0; i < patterns_size; )
  204.   {
  205.     i = line_start(i);
  206.     if (match_pattern(directory, patterns + i))
  207.     {
  208.       /* Get cmos options from pattern */
  209.  
  210.       /* Find end of pattern */
  211.       while (patterns[i] && !isspace(patterns[i]))
  212.         ++i;
  213.       if (!patterns[i])
  214.         return -1;
  215.       /* Skip spaces and tabs */
  216.       while (patterns[i] && isspace(patterns[i]))
  217.         ++i;
  218.       if (!patterns[i] || !isxdigit(patterns[i]) || !isxdigit(patterns[i+1]) ||
  219.           (patterns[i+2] && !isspace(patterns[i+2]) && !isxdigit(patterns[i+2])))
  220.         return -1;
  221.       sscanf(&patterns[i], "%x", &cmos);
  222.       return cmos;
  223.     }
  224.     i = next_line(i);
  225.   }
  226.   return -1;
  227. }
  228.  
  229. #define SLSIZE 256
  230.  
  231. /* Simple test for whether a directory contains more than n entries */
  232. /*
  233. static bool dir_more_simple(const char *directory, int n)
  234. {
  235.   bool result;
  236.   char *sl;
  237.  
  238.   sl = malloc(SLSIZE);
  239.   if (!sl)
  240.     return FALSE;
  241.   result = (!xosgbpb_dir_entries(directory, (osgbpb_string_list *) sl, 1,
  242.       n, SLSIZE, 0, &n, 0) && n);
  243.   free(sl);
  244.   return result;
  245. }
  246. */
  247.  
  248. static bool dir_more_complex(const char *directory, int n)
  249. {
  250.   int count;
  251.   int total;
  252.   int index;
  253.   char *sl;
  254.  
  255.   sl = malloc(SLSIZE + 256);
  256.   if (!sl)
  257.     return FALSE;
  258.   for (total = index = 0; index != -1 && total < n; )
  259.   {
  260.     if (xosgbpb_dir_entries(directory, (osgbpb_string_list *) sl, 64,
  261.       index, SLSIZE, 0, &count, &index))
  262.     {
  263.       free(sl);
  264.       return FALSE;
  265.     }
  266.     total += count;
  267.   }
  268.   free(sl);
  269.   return total > n;
  270. }
  271.  
  272. bool match_and_set(char const *directory)
  273. {
  274.   int cmos = match_patterns(directory);
  275.   int action = (cmos & 0xf000000) >> 24;
  276. #ifndef NDEBUG
  277.   report("cmos = 0x%x\n", cmos);
  278. #endif
  279.   if (cmos == -1)
  280.     return FALSE;
  281.   else if (cmos >= 0x1000000 && action == 1)
  282.   {
  283. #ifndef NDEBUG
  284. report("Counting dir contents\n");
  285. #endif
  286.     if (dir_more_complex(directory, (cmos & 0xff0000) >> 16))
  287.     {
  288. #ifndef NDEBUG
  289. report("More than 0x%x, setting cmos to 0x%x\n", (cmos & 0xff0000) >> 16, cmos & 0xff);
  290. #endif
  291.       cmos &= 0xff;
  292.     }
  293.     else
  294.     {
  295. #ifndef NDEBUG
  296. report("Fewer than 0x%x, setting cmos to 0x%x\n", (cmos & 0xff0000) >> 16, (cmos & 0xff00) >> 8);
  297. #endif
  298.       cmos = (cmos & 0xff00) >> 8;
  299.     }
  300.   }
  301.   cmos_set(cmos);
  302.   return TRUE;
  303. }
  304.  
  305. static const char FilerOpenDir[] = "%Filer_OpenDir ";
  306. static const int lfod = sizeof(FilerOpenDir) - 1;
  307.  
  308. /* Convert original command tail to "%Filer_OpenDir ... " */
  309. os_error const *convert_command(char const *command, char **newcom)
  310. {
  311.   int i;
  312.   int cmos;
  313.   char const *dir;
  314.   os_error const *e;
  315.   static char com[256];
  316.  
  317. #ifndef NDEBUG
  318.   report("original command=\n\"%s\"\n", command);
  319. #endif
  320.   strcpy(com, FilerOpenDir);
  321.  
  322.   while (isspace(*command)) ++command;
  323.   if (iscntrl(*command))
  324.   {
  325.     *newcom = 0;
  326.     return &syntax_error;
  327.   }
  328.  
  329.   /* Make command zero-terminated */
  330.   for (i = 0; !iscntrl(command[i]) || command[i] == '\t'; ++i)
  331.   {
  332.     if (command[i] == '\t')
  333.       com[i + lfod] = ' ';
  334.     else
  335.       com[i + lfod] = command[i];
  336.   }
  337.   com[i + lfod] = 0;
  338. #ifndef NDEBUG
  339.   report("lfod = %d, command=\n\"%s\"\n", lfod, com);
  340. #endif
  341.  
  342.   *newcom = com;
  343.   e = find_directory(command, &dir);
  344.   if (e)
  345.     return e;
  346.   cmos = match_patterns(dir);
  347.   if (cmos != -1)
  348.     cmos_set(cmos);
  349.   return 0;
  350. }
  351.